/*
 * This software code is (c) 2010 T-Mobile USA, Inc. All Rights Reserved.
 *
 * Unauthorized redistribution or further use of this material is
 * prohibited without the express permission of T-Mobile USA, Inc. and
 * will be prosecuted to the fullest extent of the law.
 *
 * Removal or modification of these Terms and Conditions from the source
 * or binary code of this software is prohibited.  In the event that
 * redistribution of the source or binary code for this software is
 * approved by T-Mobile USA, Inc., these Terms and Conditions and the
 * above copyright notice must be reproduced in their entirety and in all
 * circumstances.
 *
 * No name or trademarks of T-Mobile USA, Inc., or of its parent company,
 * Deutsche Telekom AG or any Deutsche Telekom or T-Mobile entity, may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" AND "WITH ALL FAULTS" BASIS
 * AND WITHOUT WARRANTIES OF ANY KIND.  ALL EXPRESS OR IMPLIED
 * CONDITIONS, REPRESENTATIONS OR WARRANTIES, INCLUDING ANY IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT CONCERNING THIS SOFTWARE, ITS SOURCE OR BINARY CODE
 * OR ANY DERIVATIVES THEREOF ARE HEREBY EXCLUDED.  T-MOBILE USA, INC.
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE
 * OR ITS DERIVATIVES.  IN NO EVENT WILL T-MOBILE USA, INC. OR ITS
 * LICENSORS BE LIABLE FOR LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
 * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT
 * OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF T-MOBILE USA,
 * INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * THESE TERMS AND CONDITIONS APPLY SOLELY AND EXCLUSIVELY TO THE USE,
 * MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE, ITS SOURCE OR BINARY
 * CODE OR ANY DERIVATIVES THEREOF, AND ARE SEPARATE FROM ANY WRITTEN
 * WARRANTY THAT MAY BE PROVIDED WITH A DEVICE YOU PURCHASE FROM T-MOBILE
 * USA, INC., AND TO THE EXTENT PERMITTED BY LAW.
 */

package javax.microedition.ims.core.transaction;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * User: Pavel Laboda (pavel.laboda@gmail.com)
 * Date: 5.8.2010
 * Time: 15.05.46
 */
class PrioritizedData<E> implements Comparable<PrioritizedData<?>>, ElementContainer<E> {

    enum VipStatus {
        VIP(true),
        ORDINAL(false);

        private final boolean status;

        private VipStatus(boolean status) {
            this.status = status;
        }

        boolean booleanValue() {
            return status;
        }
    }

    private final static TaskCounter TASK_COUNTER = new TaskCounter();

    private final Priority priority;
    private final E element;
    private final long counter;

    private final AtomicBoolean vipStatus = new AtomicBoolean(false);

    PrioritizedData(final Priority priority, final E element, final VipStatus vipStatus) {
        this.priority = priority;
        this.element = element;
        this.vipStatus.set(vipStatus.booleanValue());
        this.counter = TASK_COUNTER.nextCounter(priority);
    }

    PrioritizedData(final Priority priority, final E element) {
        this(priority, element, VipStatus.ORDINAL);
    }

    public E getElement() {
        return element;
    }

    public int compareTo(PrioritizedData<?> data) {

        //if two elements refer to the same object return 0 
        int retValue = 0;

        if (this != data) {
            if (vipStatus.get() == data.vipStatus.get()) {

                assert !vipStatus.get() : "More then one VIP element. this element = " + this + " compare to element = " + data;

                retValue = -priority.ordinal() + data.priority.ordinal();

                if (retValue == 0) {
                    retValue = (int) (counter - data.counter);
                }
            }
            else {
                retValue = vipStatus.get() ? -1 : 1;
            }
        }

        return retValue;
    }

    public void markVip(final VipStatus vipStatus) {
        this.vipStatus.set(vipStatus.booleanValue());
    }


    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        PrioritizedData that = (PrioritizedData) o;

        return counter == that.counter && vipStatus.get() == that.vipStatus.get() && priority == that.priority;

    }


    public int hashCode() {
        int result = priority != null ? priority.hashCode() : 0;
        result = 31 * result + (vipStatus.get() ? 1 : 0);
        result = 31 * result + (int) (counter ^ (counter >>> 32));
        return result;
    }


    public String toString() {
        return "[" +
                "" + priority +
                ":" + counter +
                ":" + element +
                ']';
    }
}
